/*
 * Copyright (c) 2024 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <devmon/driver_abi.h>
#include <dlfcn.h>
#include <gtest/gtest.h>
#include <mc/log.h>
#include <memory>
#include <test_utilities/test_base.h>
#include <unordered_map>

#include "../../../drivers/scanner/scanner/scanner.h"
#include "../test_utils/root_object.h"

using namespace dev;
using namespace devmon;

namespace drivers {
namespace scanner {
namespace test {

class scanner_test_service : public mc::engine::service {
public:
    scanner_test_service(const std::string& name) : mc::engine::service(name) {
    }
};

class ScannerAbiTest : public mc::test::TestWithEngine {
public:
    static void SetUpTestSuite() {
        TestWithEngine::SetUpTestSuite();
        m_test_service = mc::make_shared<scanner_test_service>("bmc.kepler.test_scanner_abi");
        m_test_service->init();
        m_test_service->start();

        // 创建根对象
        m_root_object = root_object::create_root_object(m_test_service.get());

        load_driver();
    }

    static void TearDownTestSuite() {
        m_test_service->stop();
        m_root_object.reset();

        if (m_driver_handle != nullptr) {
            dlclose(m_driver_handle);
            m_driver_handle = nullptr;
        }

        m_test_service.reset();
        TestWithEngine::TearDownTestSuite();
    }

    void SetUp() override {
        // 测试用例之间无需特殊设置
    }

    void TearDown() override {
        // 测试用例之间无需特殊清理
    }

    static void load_driver() {
        m_driver_handle = dlopen("./opt/bmc/drivers/libScanner.so", RTLD_LAZY);
        if (m_driver_handle == nullptr) {
            MC_THROW(mc::system_exception, "Failed to load Scanner driver: ${error}",
                     ("error", dlerror()));
        }

        register_device_driver_func func = reinterpret_cast<register_device_driver_func>(
            dlsym(m_driver_handle, "register_device_driver"));
        MC_ASSERT_THROW(func, mc::bad_function_call_exception,
                        "Failed to get register_device_driver function: ${error}",
                        ("error", dlerror()));

        device_driver_t* devices       = nullptr;
        uint8_t          devices_count = 0;
        status_t         ret           = func(&devices, &devices_count);
        MC_ASSERT_THROW(ret == STATUS_OK, mc::bad_function_call_exception,
                        "Failed to get device driver manager: ${error}", ("error", ret));

        m_devices.clear();
        m_devices.reserve(devices_count);
        for (uint8_t i = 0; i < devices_count; i++) {
            auto device_driver = std::make_shared<device_driver_t>(devices[i]);
            m_devices.emplace(device_driver->device_name, device_driver);
        }
    }

    mc::dict create_test_connector(uint8_t system_id = 1, uint8_t position = 1, uint8_t slot = 1) {
        return mc::dict{{"SystemId", system_id}, {"Position", position}, {"Slot", slot}};
    }

    mc::mutable_dict create_test_csr_object(const std::string& chip_path, uint32_t offset,
                                            uint8_t size, uint8_t mask, uint8_t type,
                                            uint32_t period) {
        return mc::mutable_dict{{"Chip", chip_path}, {"Offset", offset}, {"Size", size},
                                {"Mask", mask},      {"Type", type},     {"Period", period}};
    }

    static mc::shared_ptr<scanner_test_service>                              m_test_service;
    static std::unordered_map<std::string, std::shared_ptr<device_driver_t>> m_devices;
    static void*                                                             m_driver_handle;
    static root_object_ptr                                                   m_root_object;
};

mc::shared_ptr<scanner_test_service>                              ScannerAbiTest::m_test_service;
std::unordered_map<std::string, std::shared_ptr<device_driver_t>> ScannerAbiTest::m_devices;
void*           ScannerAbiTest::m_driver_handle = nullptr;
root_object_ptr ScannerAbiTest::m_root_object;

// ========================= 驱动注册功能测试 =========================

TEST_F(ScannerAbiTest, register_device_driver_success) {
    EXPECT_EQ(m_devices.size(), 1);
    EXPECT_TRUE(m_devices.find("Scanner") != m_devices.end());
}

TEST_F(ScannerAbiTest, device_driver_structure_validation) {
    for (const auto& [device_name, device_driver] : m_devices) {
        EXPECT_FALSE(std::string(device_driver->device_name).empty());
        EXPECT_TRUE(device_driver->ctor != nullptr);
        EXPECT_TRUE(device_driver->init != nullptr);
        EXPECT_TRUE(device_driver->start != nullptr);
        EXPECT_TRUE(device_driver->stop != nullptr);
    }
}

// ========================= Scanner设备创建测试 =========================

TEST_F(ScannerAbiTest, create_scanner_success) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner");
    ASSERT_TRUE(device != nullptr);

    Scanner* scanner_device = static_cast<Scanner*>(device);
    EXPECT_TRUE(scanner_device != nullptr);
}

TEST_F(ScannerAbiTest, create_scanner_null_service) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空服务指针应该返回nullptr
    auto device = device_driver->ctor(nullptr, "test_scanner");
    EXPECT_EQ(device, nullptr);
}

TEST_F(ScannerAbiTest, create_scanner_null_name) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    // 传入空名称应该返回nullptr
    auto device = device_driver->ctor(m_test_service.get(), nullptr);
    EXPECT_EQ(device, nullptr);
}

// ========================= Scanner设备初始化测试 =========================

TEST_F(ScannerAbiTest, init_scanner_success) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_init");
    ASSERT_TRUE(device != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t ret = device_driver->init(device, &csr_object, &connector);
    EXPECT_EQ(ret, STATUS_OK);
}

TEST_F(ScannerAbiTest, init_scanner_null_device) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t ret = device_driver->init(nullptr, &csr_object, &connector);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(ScannerAbiTest, init_scanner_null_csr_object) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_init_null_csr");
    ASSERT_TRUE(device != nullptr);

    auto connector = create_test_connector(1, 1, 1);

    status_t ret = device_driver->init(device, nullptr, &connector);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(ScannerAbiTest, init_scanner_null_connector) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_init_null_conn");
    ASSERT_TRUE(device != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);

    status_t ret = device_driver->init(device, &csr_object, nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

// ========================= Scanner设备启停测试 =========================

TEST_F(ScannerAbiTest, start_scanner_success) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_start");
    ASSERT_TRUE(device != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    status_t start_ret = device_driver->start(device);
    EXPECT_EQ(start_ret, STATUS_OK);
    
    // 停止 scanner 避免内存错误
    device_driver->stop(device);
}

TEST_F(ScannerAbiTest, start_scanner_null_device) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    status_t ret = device_driver->start(nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(ScannerAbiTest, stop_scanner_success) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_stop");
    ASSERT_TRUE(device != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    status_t start_ret = device_driver->start(device);
    ASSERT_EQ(start_ret, STATUS_OK);

    status_t stop_ret = device_driver->stop(device);
    EXPECT_EQ(stop_ret, STATUS_OK);
}

TEST_F(ScannerAbiTest, stop_scanner_null_device) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    status_t ret = device_driver->stop(nullptr);
    EXPECT_EQ(ret, STATUS_ERROR);
}

TEST_F(ScannerAbiTest, stop_scanner_without_start) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_stop_no_start");
    ASSERT_TRUE(device != nullptr);

    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    // 直接停止而不启动应该成功
    status_t stop_ret = device_driver->stop(device);
    EXPECT_EQ(stop_ret, STATUS_OK);
}

// ========================= Scanner完整生命周期测试 =========================

TEST_F(ScannerAbiTest, scanner_full_lifecycle) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    // 1. 创建设备
    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_lifecycle");
    ASSERT_TRUE(device != nullptr);

    // 2. 初始化设备
    auto csr_object = create_test_csr_object("#/MockChip", 0x100, 4, 0xFF, 1, 1000);
    auto connector  = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);

    // 3. 启动设备
    status_t start_ret = device_driver->start(device);
    EXPECT_EQ(start_ret, STATUS_OK);

    // 4. 停止设备
    status_t stop_ret = device_driver->stop(device);
    EXPECT_EQ(stop_ret, STATUS_OK);

    // 5. 再次启动设备
    status_t restart_ret = device_driver->start(device);
    EXPECT_EQ(restart_ret, STATUS_OK);

    // 6. 最终停止设备
    status_t final_stop_ret = device_driver->stop(device);
    EXPECT_EQ(final_stop_ret, STATUS_OK);
}

// ========================= Scanner边界值测试 =========================

TEST_F(ScannerAbiTest, scanner_boundary_values_min) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_boundary_min");
    ASSERT_TRUE(device != nullptr);

    // 测试最小值
    auto csr_object_min = create_test_csr_object("#/MockChip", 0, 1, 0, 0, 1);
    auto connector      = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object_min, &connector);
    ASSERT_EQ(init_ret, STATUS_OK);
    
    status_t start_ret = device_driver->start(device);
    EXPECT_EQ(start_ret, STATUS_OK);
    
    // 停止 scanner 避免内存错误，特别是对于 1ms 的极短间隔
    device_driver->stop(device);
}

TEST_F(ScannerAbiTest, scanner_boundary_values_max) {
    auto device_driver = m_devices["Scanner"];
    ASSERT_TRUE(device_driver != nullptr);

    auto device = device_driver->ctor(m_test_service.get(), "test_scanner_boundary_max");
    ASSERT_TRUE(device != nullptr);

    // 测试最大值，但使用合理的period值（10秒）
    auto csr_object_max =
        create_test_csr_object("#/MockChip", 0xFFFFFFFF, 8, 0xFF, 0xFF, 10000);
    auto connector = create_test_connector(1, 1, 1);

    status_t init_ret = device_driver->init(device, &csr_object_max, &connector);   
    EXPECT_EQ(init_ret, STATUS_OK);
}

} // namespace test
} // namespace scanner
} // namespace drivers